package com.guonl.mybatis.interceptor;

import com.alibaba.fastjson.JSON;
import com.guonl.enums.EventType;
import com.guonl.event.model.SyncSqlEvent;
import com.guonl.event.model.UserEvent;
import com.guonl.event.model.UserVO;
import com.guonl.plus.entity.UserPlus;
import com.guonl.utils.SqlUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import java.util.Objects;

@Slf4j
@Component
@Intercepts({
        @Signature(method = "update", type = Executor.class, args = {
                MappedStatement.class,
                Object.class
        })
})
public class TableDataChangeInterceptor implements Interceptor {

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget();

        Object proceed = invocation.proceed();
        try {
            MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];

            if (invocation.getArgs().length > 1) {
                Object parameter = invocation.getArgs()[1];

                if (parameter instanceof MapperMethod.ParamMap) {
                    BoundSql boundSql = mappedStatement.getBoundSql(parameter);
                    String tableName = SqlUtil.getTableName(boundSql.getSql());
                    log.info("tableName = {}", tableName);
                    String sql = SqlUtil.getSql(mappedStatement, parameter);
                    log.info("sql = {}", sql);
                    executeSql(tableName, sql);
                    return proceed;
                }

                SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
                if (SqlCommandType.INSERT.equals(sqlCommandType)) {
                    insertCommond(parameter);
                }
                if (SqlCommandType.UPDATE.equals(sqlCommandType)) {
                    updateCommond(parameter);
                }
            }


        } catch (Exception e) {
            log.warn("entity change warning: {}", e.getMessage(), e);
        } finally {
            return proceed;
        }
    }

    private void executeSql(String tableName, String sql) {
        if ("t_user".equals(tableName)) {
//            String newSql = sql.replace(tableName, "index_t_user");
            SyncSqlEvent sqlEvent = new SyncSqlEvent();
            sqlEvent.setTableName(tableName);
            sqlEvent.setExecuteSql(sql);
            applicationEventPublisher.publishEvent(sqlEvent);
        }
    }

    private void updateCommond(Object params) {
        if (Objects.isNull(params)) {
            return;
        }
        // 更新user的事件
        if (params instanceof UserPlus) {
            UserPlus user = (UserPlus) params;
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);
            UserEvent userEvent = new UserEvent(EventType.UPDATE, userVO);
            applicationEventPublisher.publishEvent(userEvent);
            log.info("[发布事件:{}] - [事件内容:{}]", EventType.UPDATE, JSON.toJSONString(userEvent));
        }
    }

    private void insertCommond(Object params) {
        if (Objects.isNull(params)) {
            return;
        }
        // 插入user的事件
        if (params instanceof UserPlus) {
            UserPlus user = (UserPlus) params;
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);
            UserEvent userEvent = new UserEvent(EventType.INSERT, userVO);
            applicationEventPublisher.publishEvent(userEvent);
            log.info("[发布事件:{}] - [事件内容:{}]", EventType.INSERT, JSON.toJSONString(userEvent));
        }
    }

}